<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>K.Sprite and K.Bitmap</title>
	<link href="tuts/index.css" rel="stylesheet" type="text/css">
</head>
<body">
	<article>
	<header>
	<h1>SPRITE and BITMAP</h1>
	</header>
	<div class="black">
    <canvas id="canvas" width="640" height="480"></canvas>
	</div>
	<section>
		<p>Now we look forward for what the K.Sprite and K.Bitmap can do. But before..,
		<h2>Preloader</h2></header>
		<p>I like to introduce you how to make class like Preloader. The class is usefull to avoid problems when a code ask for items that browser not yet load it.</p>
		<textarea class="ta400" readonly>
<code>
/*
** Author mi_kuncoco@yahoo.co.id
*/
function Preloader(){
	this.numToLoad = 0;
	this.started = false;
};
Preloader.prototype = {
	constructor:Preloader,
	numToLoad : 0,
	callback : null,
	started : false,
	/*
	** Set object source and onload function
	** then return the object
	*/
	loadSomething(obj, url){
		this.numToLoad = (this.numToLoad < 1) ? 1 : (this.numToLoad + 1);
		obj.onload = preloader.itemLoaded();
		obj.src = url;
		return obj;
	},
	/*
	** Create an Image object and set the source,
	** add onload function
	** then return the object
	*/
	loadImage : function(imageUrl) {
		return loadSomething(new Image(), imageUrl);
	},
	/*
	** Called internal
	** Check the if all items already loaded
	** Execute callback if aloading complete
	*/
	checkIfComplete : function(e){
		if (this.callback == null) return false;
		if (this.numToLoad < 1) {
			this.callback();
			this.dispose();
		}
	},
	/*
	** Called when an item loaded
	** Reduce number to load
	** Call checkIfComplete
	*/
	itemLoaded : function(){
		this.numToLoad--;
		if (this.started) this.checkIfComplete();
	},
	/*
	** Call it after you code all items to load
	** It will check if loading is complete or start to check each time a file was loaded
	*/
	start : function(){
		this.started = true;
		this.checkIfComplete();
	},
	/*
	** Auto called
	*/
	dispose:function(){
		callback = null;
		preloader = null;
	}
};
/*
** The preloader must be defined because it will be call by the class
*/
var preloader = new Preloader();
/*
** It's ready to place code now...
*/
</code>
		</textarea>
		<br/>
		<h2>Initialize K </h2></header>
		<textarea class="ta300" readonly>
K.stage.originWidth = 640;
K.stage.originHeight = 480;
K.init(document.getElementById("canvas"));
/*
** Localize canvas and context to make easy
*/
var cvs = K.canvas;
var ctx = K.context;
/*
** Create variables to strore data we will use later
*/
var drops = [];
var c0, c1, c2, c3;
/*
** Now watch the Preloader role:
*/
var texture = preloader.loadImage("res/ground.png");
var dropImg = preloader.loadImage("res/part.png");</textarea>
	</section>
	<section>
		<h2>Drawing The Graphics</h2></header>
		<p>This time we make some functions to change graphics on item click. We store it in an array named as paths</p>
		<textarea class="ta400" readonly>
var paths = [
	/*
	** Drawing a solid polygon
	*/
	function(g) {
		g.beginFill("#ff00ff");
		g.beginPath();
		g.moveTo(-32, -32);
		g.lineTo(32, -32);
		g.lineTo(0, 32);
		g.closePath();
		g.fill()
	},
	/*
	** Fill a radial gradient into a circle
	** Parameters of a circle is x, y and radius
	*/
	function(g){
		g.beginGradientFill("radial", ["#775500", "#dd8000"],[0, 1], -32, -32, 10, 64, 64, 60);
		g.beginPath();
		g.drawCircle(0, 0, 32);
		g.closePath();
		g.fill()
	},
	/*
	** Fill a linear gradient into a rectangle
	** The beginGradientFill parameters:
	** gradient type, [linear],
	** array of colors,
	** array of colors position or ratio,
	** start x, start y,
	** end x, end y
	** start and end position represent the line of gradient direction
	**
	** Parameters of rectangle is x, y, width and height
	*/
	function(g){
		g.beginGradientFill("linear", ["#003300", "#33ff00"],[0, 1], -32, -32, 64, 64);
		g.beginPath();
		g.drawRect(-32, -32, 64, 64);
		g.closePath();
		g.fill()
	},
	/*
	** Drawing a rounded-rectangle
	** The start and end position in radial gradient added by the angle of each point in degree:
	** start x, start y, start angle
	** end x, end y, end angle
	*/
	function(g){
		g.beginFill("#ff00ff");
		g.beginPath();
		g.drawRoundRect(-32, -32, 64, 64, 16, 0, 16, 0);
		g.closePath();
		g.fill()
	},
	/*
	** Another rounded rectangle
	** The rounded rectangle parameters:
	** x, y,
	** width, height,
	** topleft radius, topright radius, bottomright radius, bottomleft radius
	*/
	function(g){
		g.beginFill("#ffff00");
		g.beginPath();
		g.drawRoundRect(-32, -32, 64, 64, 0, 16, 0, 16);
		g.closePath();
		g.fill()
	},
	/*
	** Drawing a simetric polygon
	** The Syntax: drawSimetry(x, y, number of points, distance or radius)
	*/
	function(g){
		//g.lineStyle(4, "#ffffff");
		g.beginFill("#cc00ee");
		g.beginPath();
		g.drawSimetry(0, 0, 6, 32);
		g.closePath();
		g.fill()
	},
	/*
	** Drawing a star polygon
	** The Syntax: drawSimetry(x, y, number of points, outer-radius, inner-radius)
	*/
	function(g){
		g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 79, 79);
		g.beginPath();
		g.drawStar(0, 0, 5, 39, 20);
		g.closePath();
		g.fill();
	},
	/*
	** Trying to draw a bitmap/image into a rounded rectangle
	** Parameters of beginBitmapFill:
	** source image,
	** source x, source y, source width, source height,
	** target x, target y, target width, target height
	** The target rectangle is in local area
	*/
	function(g){
		g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 79, 79);
		g.beginPath();
		g.drawRoundRect(-32, -32, 64, 64, 0, 16, 0, 16);
		g.closePath();
		g.fill();
	},
	function(g){
		g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 64, 64);
		g.beginPath();
		g.drawRoundRect(-32, -32, 64, 64, 0, 12, 0, 12);
		g.closePath();
		g.fill()
	}
];
		</textarea>
	</section>
	<section>
		<h2>Event Handler to Change the Graphics</h2></header>
		<p>The following method is a variable function to change the graphics based on a Mouse Click</p>
		<textarea class="ta100" readonly>
var changePath = function(e){
	// We have to clear the graphics first:
	e.target.graphics.clear();
	paths[Math.floor(Math.random() * paths.length)](e.target.graphics);
};
		</textarea>
	</section>
	<section>
		<h2>The Loop</h2></header>
		<p>The loop actually doing:
		<li>Updating items as you wish</li>
		<li>Updating matrix to transform each items</li>
		<li>Render to context</li>
		</p>
		<p>The engine make you focus only to update items. The rest will be done by the engine when you call K.render()</p>
		<textarea class="ta300" readonly>
function step(){
	var i, o;
	
	//Updating items:
	for (i = 0; i < drops.length; i++){
		o = drops[i];
		yy = o.y + o.data.speed;
		o.y = (yy > 480) ? 0 : yy;
	}
	c1.rotation += K.P1;
	c3.rotation += K.P1;
	
	// Order engine to do the rest:
	K.render();
	
	// Call next frame:
	window.requestAnimationFrame(step, 1000/30);
}</textarea>
	</section>
	<section>
		<h2>Create Items / init app</h2></header>
		<p>The following method is a variable function to change the graphics based on a Mouse Click</p>
		<textarea class="ta400" readonly>
function init(){
	
	var i, o;
	// Create Bitmap Objects:
	var srcDrop = new K.ImageSource("dropSrc", dropImg, 0, 0, 2, 2, 0, 0);
	for (i = 0; i < 200; i++){
		o = new K.Bitmap( "drop_" + i.toString(), Math.random() * 640, Math.random() * 480, srcDrop );
		o.useTransform = true; 
		o.data.speed = Math.random() * 5;
		drops.push(o);
		K.stage.addChild(o);
	}
	
	//Create Main Container:
	c0 = new K.Sprite("c0", 320, 240);
	c0.graphics.drawBitmap(texture, -32, -32);
	K.stage.addChild(c0);
	
	//Create Sprite and add to Main Container
	c1 = new K.Sprite("c1", 100, 0);
	c1.rotation = K.P1 * 30;
	c0.addChild(c1);
	
	//Create Sprite and add to existing Sprite
	c2 = new K.Sprite("c2", 100, 0);
	c2.rotation = K.P1 * 60;
	c2.scaleX = c2.scaleY = 1.2;
	c1.addChild(c2);
	
	//Create Sprite and add to existing Sprite
	c3 = new K.Sprite("c3", 100, 0);
	c3.rotation = K.P1 * 70;
	c3.scaleX = c3.scaleY = 0.8;
	c2.addChild(c3);
	
	// Call paths to draw first graphics:
	paths[0](c1.graphics);
	paths[1](c2.graphics);
	paths[2](c3.graphics);
	
	c0.dirty = true;
	
	// Adding EventListener to each Sprite
	c1.addEventListener("click", changePath);
	c2.addEventListener(K.Events.CLICK, changePath);
	c3.addEventListener(K.Events.CLICK, changePath);
	
	// Start using the engine's inputs:
	K.EventManager.start();
	
	// Call the first loop"
	step();
};

// Set the preloader callback
preloader.callback = init();

// Start the preloader:
preloader.start();
//END
		</textarea>
	</section>
	
	</article>
	<script src="../js/K.js"></script>
	<script src="../js/Preloader.js"></script>
	<script>
(function(){

	K.stage.originWidth = 640;
	K.stage.originHeight = 480;
	K.init(document.getElementById("canvas"));
	
	var cvs = K.canvas;
	var ctx = K.context;
	
	var drops = [];
	var c0, c1, c2, c3;
	
	var texture = preloader.loadImage("res/ground.png");
	var dropImg = preloader.loadImage("res/part.png");
	
	var paths = [
		function(g) {
			g.beginFill("#ff00ff");
			g.beginPath();
			g.moveTo(-32, -32);
			g.lineTo(32, -32);
			g.lineTo(0, 32);
			g.closePath();
			g.fill()
		},
		function(g){
			g.beginGradientFill("radial", ["#775500", "#dd8000"],[0, 1], -32, -32, 10, 64, 64, 60);
			g.beginPath();
			g.drawCircle(0, 0, 32);
			g.closePath();
			g.fill()
		},
		function(g){
			g.beginGradientFill("linear", ["#003300", "#33ff00"],[0, 1], -32, -32, 64, 64);
			g.beginPath();
			g.drawRect(-32, -32, 64, 64);
			g.closePath();
			g.fill()
		},
		function(g){
			g.beginFill("#ff00ff");
			g.beginPath();
			g.drawRoundRect(-32, -32, 64, 64, 16, 0, 16, 0);
			g.closePath();
			g.fill()
		},
		function(g){
			g.beginFill("#ffff00");
			g.beginPath();
			g.drawRoundRect(-32, -32, 64, 64, 0, 16, 0, 16);
			g.closePath();
			g.fill()
		},
		function(g){
			//g.lineStyle(4, "#ffffff");
			g.beginFill("#cc00ee");
			g.beginPath();
			g.drawSimetry(0, 0, 6, 32);
			g.closePath();
			g.fill()
		},
		function(g){
			g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 79, 79);
			g.beginPath();
			g.drawStar(0, 0, 5, 39, 20);
			g.closePath();
			g.fill();
		},
		function(g){
			g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 79, 79);
			g.beginPath();
			g.drawRoundRect(-32, -32, 64, 64, 0, 16, 0, 16);
			g.closePath();
			g.fill();
		},
		function(g){
			g.beginBitmapFill(texture, 0, 0, 79, 79, -32, -32, 64, 64);
			g.beginPath();
			g.drawRoundRect(-32, -32, 64, 64, 0, 12, 0, 12);
			g.closePath();
			g.fill()
		}
	];
	
	
	
	var changePath = function(e){
		e.target.graphics.clear();
		paths[Math.floor(Math.random() * paths.length)](e.target.graphics);
	};
	
	function step(){
		var i, o, xx, yy;
		
		for (i = 0; i < drops.length; i++){
			o = drops[i];
			yy = o.y + o.data.speed;
			o.y = (yy > 480) ? 0 : yy;
		}
		
		c1.rotation += K.P1;
		c2.rotation += K.P1;
		c3.rotation += K.P1 * 3;
		
		K.render();
		
		window.requestAnimationFrame(step, 1000/30);
	}
	
	function init(){
	
		var i, o;
		
		var srcDrop = new K.ImageSource("dropSrc", dropImg, 0, 0, 2, 2, 0, 0);
		for (i = 0; i < 200; i++){
			o = new K.Bitmap( "drop_" + i.toString(), Math.random() * 640, Math.random() * 480, srcDrop );
			o.useTransform = true; 
			o.data.speed = Math.random() * 5;
			drops.push(o);
			K.stage.addChild(o);
		}
		
		c0 = new K.Sprite("c0", 320, 240);
		c0.graphics.drawBitmap(texture, -32, -32);
		K.stage.addChild(c0);
		
		c1 = new K.Sprite("c1", 100, 0);
		c1.rotation = K.P1 * 30;
		c0.addChild(c1);
		
		c2 = new K.Sprite("c2", 100, 0);
		c2.rotation = K.P1 * 60;
		c2.scaleX = c2.scaleY = 1.2;
		c1.addChild(c2);
		
		c3 = new K.Sprite("c3", 100, 0);
		c3.rotation = K.P1 * 70;
		c3.scaleX = c3.scaleY = 0.8;
		c2.addChild(c3);
		
		paths[0](c1.graphics);
		paths[1](c2.graphics);
		paths[2](c3.graphics);
		
		c0.dirty = true;
		
		c1.addEventListener("click", changePath);
		c2.addEventListener(K.Events.CLICK, changePath);
		c3.addEventListener(K.Events.CLICK, changePath);
		
		K.EventManager.start();
		
		step();
	};
	
	preloader.callback = init();
	preloader.start();
	
})();
	</script>
</body>
</html>